package com.kai.service.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.kai.service.data.request.system.CreateResourceRequest;
import com.kai.service.data.request.system.PagingResourceRequest;
import com.kai.service.data.request.system.ResourceRequest;
import com.kai.service.data.request.system.UpdateResourceRequest;
import com.kai.service.data.response.system.ResourceResponse;
import com.kai.service.enums.ResultCodeEnum;
import com.kai.service.enums.UserStatusEnum;
import com.kai.service.exception.GenericException;
import com.kai.service.system.entity.Resource;
import com.kai.service.system.entity.RoleResource;
import com.kai.service.system.mapper.ResourceMapper;
import com.kai.service.system.service.IResourceService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kai.service.system.service.IRoleResourceService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 资源管理 服务实现类
 * </p>
 *
 * @author wjk
 * @since 2021-12-11
 */
@Service
public class ResourceServiceImpl extends ServiceImpl<ResourceMapper, Resource> implements IResourceService {

    @Autowired
    private IRoleResourceService roleResourceService;

    /**
     * 根据角色id查询全部资源权限
     *
     * @param roleIds
     * @return
     */
    @Override
    public List<Resource> listRoleResource(List<Integer> roleIds) {
        if (CollectionUtils.isEmpty(roleIds)) {
            return Lists.newArrayList();
        }

        List<RoleResource> roleResourceList = roleResourceService.list(new LambdaQueryWrapper<RoleResource>()
                .in(RoleResource::getRoleId, roleIds));

        List<Integer> resourceIds = roleResourceList.stream().map(RoleResource::getResourceId).collect(Collectors.toList());

        return this.lambdaQuery()
                .in(Resource::getId, resourceIds)
                .eq(Resource::getStatus, UserStatusEnum.NORMAL.getCode())
                .list();
    }

    /**
     * 分层获取所有资源列表
     *
     * @param resourceRequest
     * @return
     */
    @Override
    public List<ResourceResponse> listHierarchyResource(ResourceRequest resourceRequest) {
        Integer roleId = resourceRequest.getRoleId();
        List<Integer> resourceIds;
        LambdaQueryWrapper<Resource> queryWrapper = new LambdaQueryWrapper<>();
        if (Objects.nonNull(roleId)){
            resourceIds = roleResourceService.list(new LambdaQueryWrapper<RoleResource>()
                    .eq(RoleResource::getRoleId, roleId)).stream().map(RoleResource::getResourceId).collect(Collectors.toList());
            queryWrapper.in(Resource::getId, resourceIds);
        }
        queryWrapper.eq(StringUtils.isNotBlank(resourceRequest.getSystemCode()), Resource::getSystemCode, resourceRequest.getSystemCode())
                .eq(Objects.nonNull(resourceRequest.getType()), Resource::getType, resourceRequest.getType())
                .eq(Objects.nonNull(resourceRequest.getStatus()), Resource::getStatus, resourceRequest.getStatus());

        // 获取全部资源
        List<Resource> resources = this.list(queryWrapper);

        List<ResourceResponse> responseList = resources.stream().map(item -> {
            ResourceResponse resourceResponse = new ResourceResponse();
            BeanUtils.copyProperties(item, resourceResponse);
            return resourceResponse;
        }).collect(Collectors.toList());

        return hierarchyResource(responseList);
    }

    /**
     * 分页获取所有资源
     *
     * @param pagingResourceRequest
     * @return
     */
    @Override
    public IPage<ResourceResponse> pagingResource(PagingResourceRequest pagingResourceRequest) {
        Integer type = pagingResourceRequest.getType();
        IPage<Resource> page = new Page<>(pagingResourceRequest.getPageIndex(), pagingResourceRequest.getPageSize());

        IPage<Resource> resourceIPage = this.page(page, new LambdaQueryWrapper<Resource>()
                .eq(StringUtils.isNotBlank(pagingResourceRequest.getSystemCode()), Resource::getSystemCode, pagingResourceRequest.getSystemCode())
                .eq(Objects.nonNull(type), Resource::getType, type));

        List<ResourceResponse> resourceResponseList = new ArrayList<>();
        resourceIPage.getRecords().forEach(resource -> {
            ResourceResponse resourceResponse = new ResourceResponse();
            BeanUtils.copyProperties(resource, resourceResponse);

            resourceResponseList.add(resourceResponse);
        });

        IPage<ResourceResponse> resourceResponseIPage = new Page<>();
        resourceResponseIPage.setRecords(resourceResponseList)
                .setCurrent(resourceIPage.getCurrent())
                .setPages(resourceIPage.getPages())
                .setSize(resourceIPage.getSize())
                .setTotal(resourceIPage.getTotal());

        return resourceResponseIPage;
    }

    /**
     * 添加资源
     *
     * @param createResourceRequest
     * @return
     */
    @Override
    @Transactional(rollbackFor = Throwable.class)
    public Boolean createResource(CreateResourceRequest createResourceRequest) {
        Date nowDate = new Date();
        List<Integer> roleIds = createResourceRequest.getRoleIds();

        Resource resource = new Resource();
        BeanUtils.copyProperties(createResourceRequest, resource);
        resource.setCreateDatetime(nowDate).setUpdateDatetime(nowDate);
        this.save(resource);

        List<RoleResource> roleResourceList = Lists.newArrayList();
        for (Integer roleId : roleIds) {
            RoleResource roleResource = new RoleResource();
            roleResource.setResourceId(resource.getId()).setRoleId(roleId);
            roleResourceList.add(roleResource);
        }
        roleResourceService.saveBatch(roleResourceList);

        return Boolean.TRUE;
    }

    /**
     * 修改资源
     *
     * @param resourceId
     * @param updateResourceRequest
     * @return
     */
    @Override
    @Transactional(rollbackFor = Throwable.class)
    public Boolean updateResource(Integer resourceId, UpdateResourceRequest updateResourceRequest) {
        List<Integer> roleIds = updateResourceRequest.getRoleIds();
        Resource resource = this.getById(resourceId);
        if (null == resource){
            throw new GenericException(ResultCodeEnum.RESOURCE_NOT_EXIST);
        }
        BeanUtils.copyProperties(updateResourceRequest, resource);
        resource.setId(resourceId).setUpdateDatetime(new Date()).updateById();

        roleResourceService.remove(new LambdaQueryWrapper<RoleResource>().eq(RoleResource::getResourceId, resourceId));
        List<RoleResource> roleResourceList = Lists.newArrayList();
        for (Integer roleId : roleIds) {
            RoleResource roleResource = new RoleResource();
            roleResource.setResourceId(resourceId).setRoleId(roleId);
            roleResourceList.add(roleResource);
        }
        roleResourceService.saveBatch(roleResourceList);

        return Boolean.TRUE;
    }

    /**
     * 切换资源启用状态
     *
     * @param resourceId
     * @param status
     * @return
     */
    @Override
    public Boolean stateSwitch(Integer resourceId, int status) {
        Resource resource = this.getById(resourceId);
        if (null == resource){
            throw new GenericException(ResultCodeEnum.RESOURCE_NOT_EXIST);
        }
        resource.setStatus(status);
        return this.updateById(resource);
    }

    /**
     * 层级资源
     *
     * @param resources
     * @return
     */
    public List<ResourceResponse> hierarchyResource(List<ResourceResponse> resources){
        // 父资源
        return resources.stream()
                .filter(resource -> resource.getParentId() == 0)
                .peek(resourceResponse -> resourceResponse.setSubResourceList(getChild(resourceResponse.getId(), resources)))
                .collect(Collectors.toList());
    }

    /**
     * 获取子资源
     *
     * @param resourceId
     * @param resources
     * @return
     */
    public List<ResourceResponse> getChild(Integer resourceId, List<ResourceResponse> resources){
        // 子资源
        return resources.stream()
                .filter(resource -> Objects.equals(resource.getParentId(), resourceId))
                .peek(resourceResponse -> resourceResponse.setSubResourceList(getChild(resourceResponse.getId(), resources)))
                .collect(Collectors.toList());
    }

}
